package cn.szsys.integration.config.filter.wrapper;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;

import java.io.*;

/**
 * @author Ryan
 * @since 2025-05-08
 **/
public class ContentCachingRequestWrapper extends HeaderBase6DecodeRequestWrapper {

    private final byte[] cachedBody;

    public ContentCachingRequestWrapper(HttpServletRequest request, ServletInputStream inputStream) throws IOException {
        super(request);
        this.cachedBody = readRequestBody(inputStream);
    }

    private byte[] readRequestBody(ServletInputStream inputStream) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        return bos.toByteArray();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new DelegatingServletInputStream(new ByteArrayInputStream(cachedBody));
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    public static class DelegatingServletInputStream extends ServletInputStream {
        private final InputStream delegate;

        public DelegatingServletInputStream(InputStream delegate) {
            this.delegate = delegate;
        }

        @Override
        public boolean isFinished() {
            try {
                return delegate.available() == 0;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener readListener) {
            throw new UnsupportedOperationException();
        }

        @Override
        public int read() throws IOException {
            return delegate.read();
        }

    }
}


